package org.pvt.gui;

import android.app.AlertDialog;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.text.InputFilter;
import android.text.format.DateFormat;
import android.util.Log;
import android.view.View;
import android.widget.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.pvt.R;
import org.pvt.model.Models;
import org.pvt.model.Queries;
import org.pvt.model.data.IdAndNameDTO;
import org.pvt.model.data.PaymentDTO;
import org.pvt.model.db.DBUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import static org.pvt.model.Model.referenceById;
import static org.pvt.model.Models.*;
import static org.pvt.model.Queries.getIdToName;
import static org.pvt.model.Queries.getNamesInTheSameOrder;

/**
 * @author Pavel Talanov
 */
public final class AddExpenseActivity extends ActivityWithMainMenu {

    @NotNull
    private final List<PaymentDTO> payments = new ArrayList<PaymentDTO>();
    @NotNull
    private final PaymentAdapter paymentAdapter = new PaymentAdapter(this);
    @Nullable
    private Long categoryId = null;

    @NotNull
    public List<PaymentDTO> getPayments() {
        return payments;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.add_expense);
        EditText totalEdit = (EditText) findViewById(R.id.totalEdit);
        setNumberFilterForEdit(totalEdit);
        ListView payment = (ListView) findViewById(R.id.payer_list);
        payment.setAdapter(paymentAdapter);
    }

    private void setNumberFilterForEdit(EditText totalEdit) {
        totalEdit.setFilters(new InputFilter[]{new DecimalDigitsInputFilter()});
    }

    @SuppressWarnings("UnusedParameters")
    public void onPickCategoryClick(@NotNull View view) {
        final List<IdAndNameDTO> idToName = getIdToName(Models.Category, getEventId(), this);
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle(R.string.chooseCategoryDialogTitle);
        builder.setItems(Queries.getNamesInTheSameOrder(idToName), new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int item) {
                setCategory(item, idToName);
            }
        });
        builder.show();
    }


    private void setCategory(int item, @NotNull List<IdAndNameDTO> idToName) {
        IdAndNameDTO idAndName = idToName.get(item);
        Button pickCategoryButton = (Button) findViewById(R.id.pickCategoryButton);
        pickCategoryButton.setText(idAndName.name);
        categoryId = idAndName.id;
    }

    public void onAddPayerClick(@NotNull View view) {
        final List<IdAndNameDTO> filtered = getListOfPeopleNotYetInTheList();
        if (filtered.isEmpty()) {
            showMessage(R.string.noPeopleLeftMessage);
        } else {
            showChoosePersonDialog(filtered);
        }
    }

    private void showMessage(int message) {
        Toast.makeText(this, message, 5).show();
    }

    private void showChoosePersonDialog(@NotNull final List<IdAndNameDTO> filtered) {
        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle(R.string.choosePersonDialogTitle);
        builder.setItems(getNamesInTheSameOrder(filtered), new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int item) {
                IdAndNameDTO correspondingItem = filtered.get(item);
                PaymentDTO payment = new PaymentDTO(correspondingItem.id);
                payment.amount = getTotalAmount() - getPaidAmount();
                payments.add(payment);
                paymentAdapter.notifyDataSetChanged();
                ListView paymentsView = (ListView) findViewById(R.id.payer_list);
                UIUtils.setListViewHeightBasedOnChildren(paymentsView);
            }
        });
        builder.show();
    }

    public void onAddExpenseClick(@NotNull View view) {
        if (categoryId == null) {
            showMessage(R.string.expenseCategoryNotSetMessage);
            return;
        }
        double eps = 0.007;
        if (getPaidAmount() < eps) {
            showMessage(R.string.zeroTotalMessage);
            return;
        }
        if (getCommentText().equals("")) {
            showMessage(R.string.commentForgottenMessage);
            return;
        }
        if (Math.abs(getPaidAmount() - getTotalAmount()) > eps) {
            showMessage(R.string.amountsDoNotMatchMessage);
            return;
        }
        doAddExpense();
        Log.d("debug", "Expense created.");
        finish();
    }

    private void doAddExpense() {
        assert categoryId != null;
        SQLiteDatabase writableDB = DBUtils.getWritableDB(this);
        writableDB.beginTransaction();
        long newExpenseId = insertNewExpense(writableDB);
        insertAllPayments(writableDB, newExpenseId);
        writableDB.setTransactionSuccessful();
        writableDB.endTransaction();
    }

    private void insertAllPayments(@NotNull SQLiteDatabase writableDB, long newExpenseId) {
        for (PaymentDTO payment : payments) {
            ContentValues paymentContentValues = new ContentValues();
            paymentContentValues.put(referenceById(Models.Expense), newExpenseId);
            paymentContentValues.put(Payment.AMOUNT, payment.amount);
            paymentContentValues.put(referenceById(Person), payment.personId);
            writableDB.insert(Models.Payment.getTableName(), null, paymentContentValues);
        }
    }

    @SuppressWarnings("AccessStaticViaInstance")
    private long insertNewExpense(@NotNull SQLiteDatabase writableDB) {
        ContentValues expenseValues = new ContentValues();
        expenseValues.put(referenceById(Event), getEventId());
        expenseValues.put(Expense.TOTAL, getTotalAmount());
        expenseValues.put(Expense.COMMENT, getCommentText());
        expenseValues.put(referenceById(Category), categoryId);
        expenseValues.put(Expense.DATE, getDateTime());
        return writableDB.insert(Models.Expense.getTableName(), null, expenseValues);
    }

    @NotNull
    private String getDateTime() {
        TimePicker timePicker = (TimePicker) findViewById(R.id.timePicker);
        DatePicker datePicker = (DatePicker) findViewById(R.id.datePicker);
        Date date = new Date();
        date.setMinutes(timePicker.getCurrentMinute());
        date.setHours(timePicker.getCurrentHour());
        date.setSeconds(0);
        date.setMonth(datePicker.getMonth());
        date.setDate(datePicker.getDayOfMonth());
        date.setYear(date.getYear());
        return DateFormat.format("yyyy-MM-dd hh:mm:ss", date).toString();
    }

    private String getCommentText() {
        EditText commentEdit = (EditText) findViewById(R.id.commentEdit);
        return commentEdit.getText().toString();
    }

    protected long getEventId() {
        return getIntent().getExtras().getLong(Models.Event.getExtrasName());
    }

    private float getTotalAmount() {
        EditText totalEdit = (EditText) findViewById(R.id.totalEdit);
        String totalText = totalEdit.getText().toString();
        return UIUtils.textToFloat(totalText);
    }

    private float getPaidAmount() {
        float total = 0;
        for (PaymentDTO payment : payments) {
            total += payment.amount;
        }
        return total;
    }

    @NotNull
    private List<IdAndNameDTO> getListOfPeopleNotYetInTheList() {
        List<IdAndNameDTO> filtered = new ArrayList<IdAndNameDTO>();
        for (IdAndNameDTO idAndName : getIdToName(Models.Person, getEventId(), this)) {
            boolean ok = true;
            for (PaymentDTO payment : payments) {
                if (payment.personId == idAndName.id) {
                    ok = false;
                    break;
                }
            }
            if (ok) {
                filtered.add(idAndName);
            }
        }
        return filtered;
    }
}
